﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using LinqToExcel;
using MassMailing.WPF.Content;
using MassMailing.WPF.Settings;

namespace MassMailing.WPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Constants

        public const string DEFAULT_FILE_PATH_TEXT = "File Path Displayed Here";

        #endregion

        #region Private Fields

        private int _attachments = 0;

        #endregion

        #region Constructors

        /// <summary>
        /// Default Constructor
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// The event handler for the click event on the btnAddAttachment.
        /// </summary>
        private void btnAddAttachment_Click(object sender, RoutedEventArgs e)
        {
            StackPanel newAttachment = new StackPanel();
            newAttachment.Orientation = Orientation.Horizontal;
            newAttachment.Name = string.Concat("spnlAttachment", _attachments);

            spnlAttachments.Children.Add(newAttachment);
            spnlAttachments.RegisterName(newAttachment.Name, newAttachment);

            TextBox txtAttachment = new TextBox();
            txtAttachment.Name = String.Concat("txtAttachment", _attachments);
            txtAttachment.TextWrapping = TextWrapping.NoWrap;
            txtAttachment.Margin = new Thickness(5);
            txtAttachment.Width = 379.554;
            txtAttachment.Text = "Attachment File Path Displayed Here";
            txtAttachment.IsReadOnly = true;
            txtAttachment.IsReadOnlyCaretVisible = true;

            newAttachment.Children.Add(txtAttachment);
            newAttachment.RegisterName(txtAttachment.Name, txtAttachment);

            Button btnAttachment = new Button();
            btnAttachment.Name = String.Concat("btnAttachment", _attachments);
            btnAttachment.Content = "Browse";
            btnAttachment.Margin = new Thickness(2.5, 0, 2.5, 0);
            btnAttachment.Tag = _attachments;
            btnAttachment.Click += new RoutedEventHandler(btnAttachment_Click);

            newAttachment.Children.Add(btnAttachment);
            newAttachment.RegisterName(btnAttachment.Name, btnAttachment);

            Button btnRemoveAttachment = new Button();
            btnRemoveAttachment.Name = String.Concat("btnRemoveAttachment", _attachments);
            btnRemoveAttachment.Content = "Remove";
            btnRemoveAttachment.Margin = new Thickness(2.5, 0, 2.5, 0);
            btnRemoveAttachment.Tag = _attachments;
            btnRemoveAttachment.Click += new RoutedEventHandler(btnRemoveAttachment_Click);

            newAttachment.Children.Add(btnRemoveAttachment);
            newAttachment.RegisterName(btnRemoveAttachment.Name, btnRemoveAttachment);

            _attachments++;
        }

        /// <summary>
        /// The event handler for the click event on all btnAttachment buttons.
        /// </summary>
        private void btnAttachment_Click(object sender, RoutedEventArgs e)
        {
            Button btnAttachment = sender as Button;

            if (btnAttachment == null)
            {
                throw new ApplicationException();
            }

            string stackPanelName = String.Concat("spnlAttachment", btnAttachment.Tag);
            string textBoxName = String.Concat("txtAttachment", btnAttachment.Tag);

            StackPanel spnlAttachment = (StackPanel)spnlAttachments.FindName(stackPanelName);
            TextBox txtAttachment = (TextBox)spnlAttachment.FindName(textBoxName);

            string filters = "All Files (*.*)|*.*";

            FileOpenDialogForTextBox(txtAttachment, String.Empty, String.Empty, filters);
        }

        /// <summary>
        /// The event handler for the click event on the btnClear button.
        /// </summary>
        private void btnClear_Click(object sender, RoutedEventArgs e)
        {
            txtToFile.Text = DEFAULT_FILE_PATH_TEXT;
            txtFrom.Text = string.Empty;
            txtSubject.Text = string.Empty;
            txtBody.Text = string.Empty;

            List<StackPanel> attachments = spnlAttachments.Children.OfType<StackPanel>().Where(x => x.Name.StartsWith("spnlAttachment")).ToList();
            foreach (StackPanel attachment in attachments)
            {
                spnlAttachments.Children.Remove(attachment);
            }
        }

        /// <summary>
        /// The event handler for the click event on all btnRemoveAttachment buttons.
        /// </summary>
        private void btnRemoveAttachment_Click(object sender, RoutedEventArgs e)
        {
            Button btnRemoveAttachment = sender as Button;

            if (btnRemoveAttachment == null)
            {
                throw new ApplicationException();
            }

            string stackPanelName = String.Concat("spnlAttachment", btnRemoveAttachment.Tag);

            StackPanel spnlAttachment = spnlAttachments.Children.OfType<StackPanel>().Single(x => x.Name.Equals(stackPanelName));
            spnlAttachments.Children.Remove(spnlAttachment);
        }

        /// <summary>
        /// The event handler for the click event on the btnSave button.
        /// </summary>
        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            MailSettings settings = MailSettings.LoadSettings();

            if (!settings.SMTPSettings.Any())
            {
                MessageBox.Show(this, "No Smtp Settings were found. Please visit File->Settings to add or modify smtp settings.", "Invalid Smtp Settings", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            List<Recipient> recipients = RetrieveRecipients();

            if (!recipients.Any())
            {
                MessageBox.Show(this, "No email addresses were found to send the email to.", "Invalid Email Addresses", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            string warningMessages = string.Empty;

            if (string.IsNullOrWhiteSpace(txtFrom.Text))
            {
                warningMessages = string.Concat(warningMessages, "No From email address was specified.", Environment.NewLine);
            }

            if (string.IsNullOrWhiteSpace(txtSubject.Text))
            {
                warningMessages = string.Concat(warningMessages, "No Subject was specified.", Environment.NewLine);
            }

            if (string.IsNullOrWhiteSpace(txtBody.Text))
            {
                warningMessages = string.Concat(warningMessages, "No Body text was specified.", Environment.NewLine);
            }

            // Append an additional newline before "Are you sure" only if there are warning messages.
            if (!string.IsNullOrEmpty(warningMessages)) warningMessages = string.Concat(warningMessages, Environment.NewLine);
            warningMessages = string.Concat(warningMessages, "Are you sure that you want to mass send this message?", Environment.NewLine);
            MessageBoxResult result = MessageBox.Show(this, warningMessages, null, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);

            if (result == MessageBoxResult.No) return;

            MassMailingMessage message = new MassMailingMessage();
            message.Attachments = RetrieveAttachments();
            message.From = txtFrom.Text;
            message.Subject = txtSubject.Text;
            message.Body = txtBody.Text.Replace("\n", "<br/>");

            SendingStatusDialogBox sendingStatusDialog = new SendingStatusDialogBox(recipients, message);
            sendingStatusDialog.Owner = this;

            sendingStatusDialog.ShowDialog();
        }
        
        /// <summary>
        /// The event handler for the click event on the btnToExcelFile.
        /// </summary>
        private void btnToExcelFile_Click(object sender, RoutedEventArgs e)
        {
            string defaultExt = ".xlsx";
            string filters = "Excel Worksheet (*.xlsx)|*.xlsx|Excel 97-2003 Worksheet (*.xls)|*.xls|CSV (Comma delimited) (*.csv)|*.csv|All Files (*.*)|*.*";

            FileOpenDialogForTextBox(txtToFile, String.Empty, defaultExt, filters);
        }

        /// <summary>
        /// The event handler for the click event on the miSettings menu item.
        /// </summary>
        private void miSettings_Click(object sender, RoutedEventArgs e)
        {
            MailSettingsDialogBox mailSettingsDialog = new MailSettingsDialogBox();

            mailSettingsDialog.Owner = this;

            mailSettingsDialog.ShowDialog();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Configure open file dialog box for the specified textbox
        /// </summary>
        /// <param name="textBox">The text box that the open dialog is being generated for.</param>
        /// <param name="defaultFileName">The default file name that open dialog should display.</param>
        /// <param name="defaultExt">The default extension that the filter should be set to.</param>
        /// <param name="filter">The filters the File Dialog will be able to display.</param>
        private void FileOpenDialogForTextBox(TextBox textBox, string defaultFileName, string defaultExt, string filter)
        {
            Microsoft.Win32.OpenFileDialog openDlg = new Microsoft.Win32.OpenFileDialog();
            openDlg.FileName = defaultFileName;
            openDlg.DefaultExt = defaultExt;
            openDlg.Filter = filter;

            // Show open file dialog box
            bool? result = openDlg.ShowDialog();

            // Only if it was successful set the result to the textbox
            if (result == true)
            {
                textBox.Text = openDlg.FileName;
            }
        }

        /// <summary>
        /// Retrieve a string list of attachments based on the attachment text boxes in the stack panels.
        /// </summary>
        /// <returns>A list of strings representing the attachments.</returns>
        private List<string> RetrieveAttachments()
        {
            List<string> results = new List<string>();
            IEnumerable<StackPanel> attachments = spnlAttachments.Children.OfType<StackPanel>().Where(x => x.Name.StartsWith("spnlAttachment"));

            foreach (StackPanel spnlAttachment in attachments)
            {
                TextBox txtAttachment = spnlAttachment.Children.OfType<TextBox>().Where(x => x.Name.StartsWith("txtAttachment")).SingleOrDefault();
                if (txtAttachment == null || string.IsNullOrWhiteSpace(txtAttachment.Text)) continue;
                results.Add(txtAttachment.Text);
            }

            return results;
        }

        /// <summary>
        /// Retrieves the recipients based on the file specified in the txtToFile textbox.
        /// </summary>
        /// <returns>A list of recipients based on the txtToFIle file.</returns>
        private List<Recipient> RetrieveRecipients()
        {
            if (string.IsNullOrWhiteSpace(txtToFile.Text) || txtToFile.Text.Equals(DEFAULT_FILE_PATH_TEXT))
            {
                return new List<Recipient>();
            }

            ExcelQueryFactory excel = new ExcelQueryFactory();
            excel.FileName = txtToFile.Text;
            excel.AddMapping<Recipient>(x => x.EmailAddress, "Email");

            List<Recipient> recipients = excel.Worksheet<Recipient>().ToList();
            List<Recipient> result = new List<Recipient>();
            foreach (Recipient recipient in recipients)
            {
                if (string.IsNullOrWhiteSpace(recipient.EmailAddress)) continue;
                result.Add(recipient);
            }

            return result;
        }

        #endregion
    }
}
